/**
 * Copyright 2000 self.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 *
 * @author Ashin Wimalajeewa
 */
package self.amigo.elem.uml;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;

import self.awt.*;
import self.awt.painter.*;
import self.gee.*;
import self.lang.*;
import self.xml.*;

import self.amigo.elem.*;

import org.w3c.dom.*;

abstract public class ASequenceDiagramElement extends ARectangularLinkable {
//  final static public Font NAME_FONT = new Font( "Arial", 0, 10 );
  final static public Font TERM_FONT = new Font( "Arial", 0, 30 );
  final static public String NAME_PROP = "name";
  final static public String TERM_PROP = "terminating";
  final static public String LEN_PROP  = "length";

  public ASequenceDiagramElement() {
    delegate =  constructDelegate();
    setDelegate( delegate );
  }

  abstract protected ARectangularHandledElement constructDelegate();
  abstract protected String getDefaultName();

  abstract class AEssential extends ARectangularHandledElement {
    protected String  name = getDefaultName();
    protected boolean isTermating = false;
    protected int     length = 50;
    protected Point     messageHistoryStart = new Point();
    protected Point     messageHistoryEnd = new Point();

    transient protected TextContext ctxText = new TextContext();
    protected LineContext ctxLine = new LineContext();

    protected TextPainter textPainter;
    protected LinePainter linePainter;

    public AEssential() {
      setInitialBounds();
      resetFrame();
    }

    abstract protected void setInitialBounds();
    abstract protected void paintFrame( Graphics surface );
    abstract protected boolean isTextUnderlined();
    abstract protected void resetFrame();
    abstract protected void resizeToMinIfRequired();
    abstract protected void resizeMessageHistory( int y );

    public void       setLayer( IDiagramLayer layerToDrawOn, boolean add ) {
      super.setLayer( layerToDrawOn, add );
      textPainter = (TextPainter) PainterManager.getPainterForOwner(
                                          layer, TextPainter.class );
      linePainter = (LinePainter) PainterManager.getPainterForOwner(
                                          layer, LinePainter.class );
    }

    public void       paint( Graphics surface ) {
      ctxText.setFontBase( surface.getFont() );
      paintFrame( surface );
      linePainter.paint( surface, ctxLine, outlineOnly );
      if ( isTermating ) {
        surface.setFont( TERM_FONT );
        surface.drawString( "X", messageHistoryEnd.x-10, messageHistoryEnd.y+20 );
      }
    }

    public void       getHandlePoints( java.util.List store ) {
      super.getHandlePoints( store );
      store.add( messageHistoryEnd );
    }

    public void       resize( int x, int y, Point[] handle, MouseEvent e, int dragState ) {
      if ( dragState == IGraphicElement.DS_AFTER_LAST ) {
        super.resize( x, y, handle, e, dragState );
        return;
      }

      if ( handle[0] == messageHistoryEnd ) {
        resizeMessageHistory( y );
        return;
      }

      layer.beginUpdate();
      super.resize( x, y, handle, e, dragState );
      resizeToMinIfRequired();
      resetFrame();
      layer.endUpdate();
    }

    // IEditableElement support
    public void       getProperties( Map store ) {
      store.put( NAME_PROP, name );
      store.put( TERM_PROP, isTermating ? Boolean.TRUE: Boolean.FALSE );
//      store.put( LEN_PROP, "" + length );
    }

    public void       setProperties( Map data ) {
      name = (String) data.get( NAME_PROP );
      Boolean isTerm = (Boolean) data.get( TERM_PROP );
      isTermating = isTerm.booleanValue();
//      String lenAsString = (String) data.get( LEN_PROP );
//      length = Integer.parseInt( lenAsString );
      layer.setDirty();
    }

    // IPersistentElement support
    public void readFrom( Node self, HashMap idObjLookUp ) throws DOMException {
      super.readFrom( self, idObjLookUp );
      name = DomUtils.getElementAttribute( self, NAME_PROP );
      String termAsString = DomUtils.getElementAttribute( self, TERM_PROP );
      isTermating = BooleanUtils.toValue( termAsString );
      String lenAsString = DomUtils.getElementAttribute( self, LEN_PROP );
      length = Integer.parseInt( lenAsString );
      resetFrame();
    }

    public void writeTo( Document doc, Element self, HashMap objIdLookup ) throws DOMException {
      super.writeTo( doc, self, objIdLookup );
      DomUtils.setElementAttribute( self, NAME_PROP, name );
      DomUtils.setElementAttribute( self, TERM_PROP, "" + isTermating );
      DomUtils.setElementAttribute( self, LEN_PROP, "" + length );
    }

    protected class TextContext extends ATextRenderInfoAdapter {
      private Font nameFont;

      public TextContext() {
        format = ITextRenderInfo.WRAPPED_FORMAT | ITextRenderInfo.CENTERED_FORMAT;
        if ( isTextUnderlined() )
          format |= ITextRenderInfo.UNDERLINE_FORMAT;
      }

      public void setFontBase( Font f ) {
        int style = f.getStyle();
        if ( f.isItalic() )
          style ^= Font.ITALIC;
        nameFont = new Font( f.getName(), style, f.getSize() + 1 );
      }

      public String     getText() {
        return name;
      }

      public Rectangle  getBounds() {
        return fig;
      }

      public Font       getFont() {
        return nameFont;
//        return NAME_FONT;
      }

      public Color      getColor() {
        return frameColor;
      }
    }

    protected class LineContext implements ILineRenderInfo, Serializable {
    	
    	/**
    	 * If the internal state of this class ever changes in such a way that it can't be defaulted,
    	 * then the {@link #serialVersionUID} should be incremented to ensure serialized instances cleanly fail.  
    	 */
    	private static final long serialVersionUID = 1;
    	
      private ArrayList points = new ArrayList();

      public Color getColor() {
        return frameColor;
      }

      public LineContext() {
        points.add( messageHistoryStart );
        points.add( messageHistoryEnd );
      }

      public boolean isDashed() {
        return true;
      }

      public float getWidth() {
        return 1.0f;
      }

      public java.util.List getPoints() {
        return points;
      }

      public String getLineName() {
        return null;
      }

      public String getLineHeader() {
        return null;
      }

      public int getSideAHead() {
        return ILineRenderInfo.NO_HEAD;
      }

      public String getSideAMajor() {
        return null;
      }

      public String getSideAMinor() {
        return null;
      }

      public int getSideBHead() {
        return ILineRenderInfo.NO_HEAD;
      }

      public String getSideBMajor() {
        return null;
      }

      public String getSideBMinor() {
        return null;
      }

      public int getHeadDiameter() {
        return 12;
      }
    }
  }
}
